#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string>
#include <vector>
#include <list>
using namespace std;

//class Student
//{
//public:
//	// 进⼊校园/图书馆/实验室刷⼆维码等⾝份认证
//	void identity()
//	{
//		// ...
//	}
//	// 学习
//	void study()
//	{
//		// ...
//	}
//protected:
//	string _name = "peter"; 
//	// 姓名
//	//地址
//	string _address;
//	string _tel;
//	int _age = 18;
//	int _stuid;
//};
//class Teacher
//{
//public:
//	// 进⼊校园/图书馆/实验室刷⼆维码等⾝份认证
//
//	void identity()
//	{
//		// ...
//	}
//	// 授课
//	void teaching()
//	{
//		//...
//	}
//protected:
//	string _name = "张三";// 姓名
//	// 年龄
//
//	int _age = 18;
//	string _address;
//	string _tel;
//	string _title;
//};
//
//class Person
//{
//public:
//	// 进⼊校园/图书馆/实验室刷⼆维码等⾝份认证
//	void identity()
//	{
//		cout << "void identity()" << _name << endl;
//	}
//protected:
//	string _name = "张三";  // 姓名
//	string _address; // 地址
//	string _tel; //电话
//	int _age = 18; //年龄
//};
//
//class Student : public Person
//{
//public:
//	// 学习
//	void study()
//	{
//		// ...
//	}
//protected:
//	int _stuid;
//};
////学号
//
//class Teacher : public Person
//{
//public:
//	// 授课
//
//	void teaching()
//	{
//		//...
//	}
//protected:
//	string title;// 职称
//};
//int main()
//{
//	Student s;
//	Teacher t;
//	s.identity();
//	t.identity();
//	return 0;
//}

// 实例演⽰三种继承关系下基类成员的各类型成员访问关系的变化
//class Person
//{
//public://公有
//	void Print()
//	{
//		cout << _name << endl;
//	}
//protected://保护
//	string _name = "张三"; // 姓名
//
//private://私有
//	int _age = 18; //年龄
//};
//struct Student :  Person//不写访问限定符默认是私有
//{
//public:
//protected:
//	int _stunum; // 学号
//
//};
//int main()
//{
//	Student s;
//	//不可以调用Print函数,因为继承方式是私有
//	//公有碰私有编程私有
//	s.Print();
//	return 0;
//}

//namespace hao
//{
//	//template<class T>
//	//class vector
//	//{};
//	// stack和vector的关系，既符合is - a，也符合has - a
//	template<class T>
//	class stack : public std::vector<T>
//	{
//	public:
//		void push(const T& x)
//		{
//			//基类是类模板时，需要指定⼀下类域，
//			//否则编译报错: error C3861 : “push_back”:找不到标识符
//            //因为stack<int>实例化时，也实例化vector<int>了
//            // 但是模版是按需实例化，push_back等成员函数未实例化，所以找不到
//            vector<T>::push_back(x);
//            //push_back(x);
//        }
//        void pop()
//        {
//            vector<T>::pop_back();
//        }
//        const T& top()
//        {
//            return vector<T>::back();
//        }
//        bool empty()
//        {
//            return vector<T>::empty();
//        }
//    };
//}
//int main()
//{
//    hao::stack<int> st;
//    st.push(1);
//    st.push(2);
//    st.push(3);
//    while (!st.empty())
//    {
//        cout << st.top() << " ";
//        st.pop();
//    }
//    return 0;
//}
/*
类模板调用,因为编译器进行编译的时候,发现了调用了push_back,就只会去当前的作用域中
去找,发现找不到就回去父类中去找,但是父类没有实例化,不能去找,因为里面很多东西都没
有确定。
别只看继承的时候实例化vector了,但是实例化的时候不是把所有的都实例化,而是按需实例化,
用哪个成员函数才会实例化哪个成员函数,
*/

//template <class Container>
//void Print(const Container& c)
//{
//	//const_iterator可能是静态成员变量,也可能是内嵌类型(内部类,typedef)
//	//typename Container::const_iterator it = c.begin();
//	//Container::const_iterator如果是类型,就没问题,如果是静态成员变量,这个
//	//语法就是有问题的,如果Container是具体的类,就没问题,可恰恰这里是模板,
//	//类模板没有实例化,也不能去里面找东西(vector<T>),编译报错就是无法确认
//	//Container::const_iterator到底是成员变量还是类型,加typename就是告诉
//	//编译器,后面的是类型
//	auto it = c.begin();//auto代表的就是类型,只是说没有现显示写,根据右边自动推导
//	while (it != c.end())
//	{
//		cout << *it << " ";
//	}
//	cout << endl;
//}
//int main()
//{
//	vector<int> v1 = { 1, 2, 3, 4 };
//	list<int> l1 = { 1,2,3,4 };
//	Print(v1);
//	Print(l1);
//	return 0;
//}
/*
前面必须加typename才能编译通过,类模板中我们要去取这个类型,但是不加typename
编译器是编不过去的,编不过去的原因就是,用一个类去取这个,有两种可能性,有可能
是个静态成员变量,也有可能是个内嵌类型,
模板,没有实例化的类模板是不能去里面找东西的,只有实例化了以后才能去找,
*/

//class Person
//{
//protected:
//	string _name; // 姓名
//	string _sex;  // 性别
//public:
//	int _age = 18;  // 年龄
//
//};
//class Student : public Person
//{
//public:
//	int _No; // 学号
//};
//int main()
//{
//	Student sobj;
//	//赋值兼容转换,特殊处理
//	// 1.派⽣类对象可以赋值给基类的指针/引⽤
//	Person * pp = &sobj;
//	Person& rp = sobj;
//	rp._age++;
//	//派生类对象可以赋值给基类的对象是通过调用
//	Person pobj = sobj;//没有产生临时对象,赋值兼容转换,也叫做切割或者切片
//	//2.基类对象不能赋值给派生类对象，这里会编译报错
//	//sobj = pobj;
//
//	double d = 1.1;//类型转换会产生临时对象
//	//i引用的是临时变量,临时变量具有常属性,所有前面得加const
//	//本质是权限的放大
//	const int& i = d;
//
//	//单参数构造支持隐式类型转换
//	//先转换成string,然后拷贝给s,构造+拷贝构造编译器优化成直接构造
//	string s = "hello";
//	//临时对象具有常属性
//	const string& s = "hello";
//	return 0;
//}

// Student的num和Person的_num构成隐藏关系，可以看出这样代码虽然能跑，但是非常容易混淆
//class Person
//{
//protected:
//	string _name = "⼩李⼦"; // 姓名
//	int _num = 111;//⾝份证号
//};
//class Student : public Person
//{
//public:
//	void Print()
//	{
//		cout << " 姓名:" << _name << endl;
//		cout << "⾝份证号:"<<Person::_num<< endl;//这样写还是能访问到的
//		cout << "学号: " << _num << endl;
//	}
//protected:
//	int _num = 999; //学号
//};
/*
Student和Person里面有一个同名成员_num,Person中的_num表示的是身份证号,而Student中的_num
表示的是学号,那我们访问_num访问的是Student中的_num,因为当派生类和基类有同名成员的时候
就会屏蔽基类对同名成员的直接访问,从语法编译的角度来说任何一个变量编译器在用的时候都得
查找它的出处,或者至少得有它的声明,比如有一个x,查找的时候先在该类中去找,该类中没有的话
就去父类中找,父类中没有的话就去全局找,全局中还没有的话就报错,所以这里被隐藏的核心原因
也是一样,用_num的时候先在派生类当中找,派生类当中找到了就用它,不用去基类中找,派生类当中
没找到就会去基类中找,所以派⽣类成员将屏蔽基类对同名成员的直接访问，这种情况叫隐藏,如果
指定作用域还是能够访问到的。
*/
//class A
//{
//public:
//	void fun()
//	{
//		cout << "func()" << endl;
//	}
//};
//class B : public A
//{
//public:
//	void fun(int i)
//	{
//		cout << "func(int i)" << i << endl;
//	}
//};
//int main()
//{
//	B b;
//	b.fun(10);
//	b.fun();
//	//b.A::fun(); //必须指定类域
//	return 0;
//};


//class Person
//{
//public:
//    //Person(const char* name)
//    Person(const char* name = "peter")
//        : _name(name)
//    {
//        cout << "Person()" << endl;
//    }
//        
//    Person(const Person& p)
//        : _name(p._name)
//    {
//        cout << "Person(const Person& p)" << endl;
//    }
//
//    Person& operator=(const Person& p)
//    {
//        cout << "Person operator=(const Person& p)" << endl;
//        if (this != &p)
//            _name = p._name;
//
//        return *this;
//    }
//
//    ~Person()
//    {
//        cout << "~Person()" << endl;
//    }
//protected:
//    string _name; // 姓名
//};
//
//class Student : public Person
//{
//public:
//    Student(int num, const char* addres, const char* name)//父类没有默认构造就得显示写
//        :_num(num)
//        , _address(addres)
//        //,_name(name)//初始化父类的时候不能这样写,要当成一个整体
//        , Person(name)//就像定义一个匿名对象似的
//    {}
//protected:
//    int _num; //学号
//    string _address;
//};
////不写,编译器默认生成的行为是什么?
////默认生成不符合我们需求,自己写,得怎么写?
////
////特点:子类中继承下来的父类成员当做一个整体对象
////构造
////默认构造:子类成员,内置类型(有缺省值就用,没有不确定)和自定义类型(默认构造)
////+父类成员(必须调用父类默认构造函数),如果父类没有默认构造,派生类的默认构造
////不能默认生成,那么我们就必须显示的写
//int main()
//{
//    Student s1(18,"张三","西安");
//
//    return 0;
//}
///*
//初始化列表是根据声明的顺序走到,再派生类中父类是声明在最前面的
//*/


//class Person
//{
//public:
//    //Person(const char* name)
//    Person(const char* name = "peter")
//        : _name(name)
//    {
//        cout << "Person()" << endl;
//    }
//
//    Person(const Person& p)
//        : _name(p._name)
//    {
//        cout << "Person(const Person& p)" << endl;
//    }
//
//    Person& operator=(const Person& p)
//    {
//        cout << "Person operator=(const Person& p)" << endl;
//        if (this != &p)
//            _name = p._name;
//
//        return *this;
//    }
//
//    ~Person()
//    {
//        cout << "~Person()" << endl;
//    }
//protected:
//    string _name; // 姓名
//};
//
//class Student : public Person
//{
//public:
//    Student(int num, const char* addres, const char* name)
//        :_num(num)
//        , _address(addres)
//        , Person(name)
//    {}
//    //拷贝构造
//    Student(const Student& s)
//        : Person(s)
//        , _num(s._num)
//        , _address(s._address)
//    {
//        cout << "Student(const Student& s)" << endl;
//    }
//protected:
//    int _num;
//    string _address;
//};
////拷贝构造:子类成员, 内置类型(有缺省值就用, 没有不确定)和自定义类型(默认构造)
////+父类成员(必须调用父类的拷贝构造)
//int main()
//{
//    Student s1(18, "张三", "西安");
//    Student s2(s1);//这里的拷贝构造不用我们写,默认生成的就够用,
//    //如果是深拷贝的话,拷贝构造和赋值需要自己写
//    return 0;
//}


//class Person
//{
//public:
//    //Person(const char* name)
//    Person(const char* name = "peter")
//        : _name(name)
//    {
//        cout << "Person()" << endl;
//    }
//
//    Person(const Person& p)
//        : _name(p._name)
//    {
//        cout << "Person(const Person& p)" << endl;
//    }
//
//    Person& operator=(const Person& p)
//    {
//        cout << "Person operator=(const Person& p)" << endl;
//        if (this != &p)
//            _name = p._name;
//
//        return *this;
//    }
//
//    ~Person()
//    {
//        cout << "~Person()" << endl;
//    }
//protected:
//    string _name; // 姓名
//};
//
//class Student : public Person
//{
//public:
//    Student(int num, const char* addres, const char* name)
//        :_num(num)
//        , _address(addres)
//        , Person(name)
//    {}
//    //拷贝构造
//    Student(const Student& s)
//        : Person(s)
//        , _num(s._num)
//        , _address(s._address)
//    {
//        cout << "Student(const Student& s)" << endl;
//    }
//    //赋值重载
//    Student& operator=(const Student& s)
//    {
//        cout << "Student& operator=(const Student& s)" << endl;
//        if (this != &s)
//        {
//            _num = s._num;
//            _name = s._name;
//            _address = s._address;
//            Person::operator=(s);//构成隐藏,必须指定类域才能调用基类的operator=
//        }
//        return *this;
//    }
//protected:
//    int _num;
//    string _address;
//};
////拷贝构造:子类成员, 内置类型(有缺省值就用, 没有不确定)和自定义类型(默认构造)
////+父类成员(必须调用父类的拷贝构造)
//int main()
//{
//    Student s1(18, "张三", "西安");
//    Student s2(s1);
//    Student s3(19, "李四", "西安");
//    s1 = s3;//默认生成的拷贝构造是ok的,那么默认生成的赋值重载也是ok的,因为
//    //拷贝构造和赋值重载的行为是一样的,如果是深拷贝类型就得自己写
//    return 0;
//}

//class Person
//{
//public:
//    //Person(const char* name)
//    Person(const char* name = "peter")
//        : _name(name)
//    {
//        cout << "Person()" << endl;
//    }
//
//    Person(const Person& p)
//        : _name(p._name)
//    {
//        cout << "Person(const Person& p)" << endl;
//    }
//
//    Person& operator=(const Person& p)
//    {
//        cout << "Person operator=(const Person& p)" << endl;
//        if (this != &p)
//            _name = p._name;
//
//        return *this;
//    }
//
//    ~Person()
//    {
//        cout << "~Person()" << endl;
//    }
//protected:
//    string _name; // 姓名
//};
//
//class Student : public Person
//{
//public:
//    Student(int num, const char* addres, const char* name)
//        :_num(num)
//        , _address(addres)
//        , Person(name)
//    {}
//    //拷贝构造
//    Student(const Student& s)
//        : Person(s)
//        , _num(s._num)
//        , _address(s._address)
//    {
//        cout << "Student(const Student& s)" << endl;
//    }
//    //赋值重载
//    Student& operator=(const Student& s)
//    {
//        cout << "Student& operator=(const Student& s)" << endl;
//        if (this != &s)
//        {
//            _num = s._num;
//            _name = s._name;
//            _address = s._address;
//            Person::operator=(s);
//        }
//        return *this;
//    }
//    //析构函数 - 有资源需要清理就必须写析构函数
//    ~Student()
//    {
//        cout << "~Student()" << endl;
//        //delete[] _ptr;
//        //构造函数不能显示调用,要显示调用就必须借用定位new的东西,析构是可以显示调用的
//        //~Person();
//        //这里由于多态的原因,析构的函数会被特殊处理,所以这样调是调不到的,析构函数会被
//        //特殊处理成destructor(),也就是说析构函数的名称不是~Student(),会被处理成~Student()
//        //会被特殊处理成~Student()也就意味这这两个构成隐藏关系,所以显示调是调不到的,所以
//        //想显示调就得指定类域
//        //Person::~Person();
//        //析构不需要写,子类析构函数结束后,会自动调用父类析构
//        
//    }
//protected:
//    int _num;
//    string _address;
//    //int* _ptr = new int(10);
//};
////析构:子类成员 内置类型(不处理)和自定义类型(调用他的析构) + 父类成员(调用他的析构)
////自己实现的话,注意不需要显示调用父类析构,子类析构函数结束后,会自动调用父类析构
//int main()
//{
//    Student s1(18, "张三", "西安");
//    Student s2(s1);
//    Student s3(19, "李四", "西安");
//    s1 = s3;
//    //析构的话先析构s3,后定义的先析构
//    return 0;
//}

// C++11的⽅法
//class Base final
//{
//public:
//    void func5() { cout << "Base::func5" << endl; }
//protected:
//    int a = 1;
//private:
//};
//class Derive :public Base
//{
//    void func4() { cout << "Derive::func4" << endl; }
//protected:
//    int b = 2;
//};
//int main()
//{
//    //Base b;
//    Derive d;
//    return 0;
//}

/*派生类的构造必须调用父类的构造,间接的限制了派生类就生成不了对应的对象*/

//class Student;
//class Person
//{
//public:
//	friend void Display(const Person& p, const Student& s);
//protected:
//	string _name; // 姓名
//
//};
//class Student : public Person
//{
//	//friend void Display(const Person& p, const Student& s);
//protected:
//	int _stuNum; // 学号
//
//};
//void Display(const Person& p, const Student& s)
//{
//	cout << p._name << endl;
//	cout << s._stuNum << endl;
//}
//int main()
//{
//	Person p;
//	Student s;
//	// 编译报错：error C2248 : “Student::_stuNum” :无法访问protected成员
//	// 解决方案：Display也变成Student的友元即可
//	Display(p, s);
//	return 0;
//}


//class Person
//{
//public:
//	string _name;
//	static int _count;
//};
//int Person::_count = 0;
//class Student : public Person
//{
//protected:
//	int _stuNum;
//};
//int main()
//{
//	Person p;
//	Student s;
//	// 这里的运行结果可以看到非静态成员_name的地址是不⼀样的
//	// 说明派生类继承下来了，父派生类对象各有⼀份
//	cout << &p._name << endl;
//	cout << &s._name << endl;
//	//这里的运行结果可以看到静态成员_count的地址是⼀样的
//	//说明派生类和基类共用同⼀份静态成员
//	cout << &p._count << endl;
//	cout << &s._count << endl;
//	//公有的情况下，⽗派⽣类指定类域都可以访问静态成员
//	cout << &Person::_count << endl;
//	cout << &Student::_count << endl;
//	return 0;
//}

//class Person
//{
//public:
//	string _name; // 姓名
//};
//class Student : /*virtual*/ public Person
//{
//protected:
//	int _num; //学号
//};
//class Teacher : /*virtual*/ public Person
//{
//protected:
//	int _id; // 职⼯编号
//};
//class Assistant : public Student, public Teacher
//{
//protected:
//	string _majorCourse; // 主修课程
//};
//int main()
//{
//	// 编译报错：error C2385 :对“_name”的访问不明确
//
//	Assistant a;
//	//a._name = "peter";
//	// 需要显⽰指定访问哪个基类的成员可以解决⼆义性问题，但是数据冗余问题⽆法解决
//	a.Student::_name = "xxx";
//	a.Teacher::_name = "yyy";
//	return 0;
//}


//解决数据冗余,二义性
//class Person
//{
//public:
//	string _name; // 姓名
//	/*int _tel;
//	int _age;
//	string _gender;
//	string _address;*/
//	// ...
//};
////使⽤虚继承Person类
//class Student : virtual public Person
//{
//protected:
//	int _num; //学号
//};
////使用虚继承Person类
//class Teacher : virtual public Person
//{
//protected:
//	int _id; //职工编号
//};
//// 教授助理
//class Assistant : public Student, public Teacher
//{
//protected:
//	string _majorCourse; // 主修课程
//};
//int main()
//{
//	//使⽤虚继承，可以解决数据冗余和⼆义性
//	Assistant a;
//	a._name = "peter";
//	return 0;
//}

//class Person
//{
//public:
//	Person(const char* name)
//		:_name(name)
//    {}
//    string _name; // 姓名
//};
//class Student : virtual public Person
//{
//public:
//    Student(const char* name, int num)
//        :Person(name)
//        , _num(num)
//    {}
//protected:
//    int _num; //学号
//};
//class Teacher : virtual public Person
//{
//public:
//    Teacher(const char* name, int id)
//        :Person(name)
//        , _id(id)
//    {}
//protected:
//    int _id; //职工编号
//};
////不要去玩菱形继承
//class Assistant : public Student, public Teacher
//{
//public:
//       Assistant(const char* name1, const char* name2, const char* name3)
//               :Person(name3)
//               ,Student(name1, 1)
//               ,Teacher(name2, 2)
//       {}
//protected:
//       string _majorCourse; // 主修课程 
//};
//class A
//{};
//class B
//{
//private:
//    A _a;
//};
//int main()
//{
//    // 思考⼀下这里a对象中_name是"张三", "李四", "王五"中的哪⼀个？        
//    Assistant a("张三", "李四", "王五");
//    return 0;
//}
/*
子类,派生类要实现构造函数的特点就是复用,自己的成员自己正常处理,父类的成员一定要调用
父类的构造函数,调了三次的Person的构造,一次是子类自己调的,两次是调用父类的构造去调的
1.Person的构造走三次还是走一次
这里不可能走三次,走三次没有意义,因为已经是虚继承了,虚继承只有一份Person,那调用一次
构造函数就可以了,所以这里调用Student和Teacher的话它不会去走Person的构造,不会走但是
还要写,因为Assistant这个类要用
2.Person的里面的_name,到底是张三,还是李四,还是王五呢?
王五
所以不要去完菱形继承,菱形继承虽然解决了数据的冗余性,但是里面的坑多着呢,
*/

//class Base1 { public:  int _b1; };
//class Base2 { public:  int _b2; };
//class Derive : public Base1, public Base2 { public: int _d; };
//int main()
//{
//    Derive d;
//    Base1* p1 = &d;
//    Base2* p2 = &d;
//    Derive* p3 = &d;
//    return 0;
//}

// Tire(轮胎)和Car(⻋)更符合has - a的关系
class Tire {
protected:
	string _brand = "Michelin";  // 品牌
	//尺⼨
	size_t _size = 17;
};
class Car {
protected:
	string _colour = "⽩⾊";           
	string _num = "陕ABIT00";         
	Tire _t1;
	Tire _t2;
	Tire _t3;
	Tire _t4;
};
class BMW : public Car {
public:
	void Drive() {
		cout << "好开操控" << endl; 
	}
};
// Car和BMW / Benz更符合is - a的关系
class Benz : public Car {
public:
	void Drive() {
		cout << "好坐舒适" << endl; 
	}
};
template<class T>
class vector
{};
// stack和vector的关系，既符合is - a，也符合has - a
template<class T>
class stack : public vector<T>
{};
template<class T>
class stack
{
public:
	vector<T> _v;
};
int main()
{

	return 0;
}